package com.example.crowdfunding.mvc.config;

import com.example.crowdfunding.constant.CrowdConstant;
import com.example.crowdfunding.utils.CrowdUtils;
import com.example.crowdfunding.utils.ResultEntity;
import com.example.crowdfunding.utils.exception.AccessForbiddenException;
import com.example.crowdfunding.utils.exception.RegisterFailedException;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 基于注解的自定义异常解析器
 */
@ControllerAdvice // 表示这个一个基于注解的，处理异常的类
public class CrowdExceptionResolver {

    /**
     * The Logger.
     */
    Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 捕获异常并返回异常信息
     *
     * @param exception 异常
     * @param request   请求，用来判断是否为ajax请求
     * @param resp      响应，用来回写数据给页面
     * @return 模型视图 model and view
     * @throws IOException IO异常
     */
    @ExceptionHandler(value = Exception.class) // 表示这个方法能处理的异常类型
    public ModelAndView ExceptionResolver(
            // 实际捕获的异常
            Exception exception,
            // 当前请求
            HttpServletRequest request,
            // 响应对象
            HttpServletResponse resp
    ) throws IOException {

        // 打印异常信息
        exception.printStackTrace();
        // 模型和视图
        ModelAndView modelAndView = new ModelAndView();
        // 视图名
        String viewName = "system-error";
        logger.warn("异常的类型 = " + exception.getClass().getSimpleName() + " 描述 = " + exception.getMessage());

        // 判断异常类型
        if (exception instanceof RegisterFailedException) {
            viewName = "admin-add";

        }
        if (exception instanceof AccessForbiddenException) {
            viewName = "admin-login";

        }
        return commonResolver(viewName, exception, request, resp, modelAndView);
    }

    private ModelAndView commonRequestResolver(String viewName, ModelAndView modelAndView, Exception exception) {

        modelAndView.setViewName(viewName);
        modelAndView.addObject(CrowdConstant.ATTR_NAME_EXCEPTION, exception);
        return modelAndView;
    }

    private void ajaxRequestResolver(Exception exception, HttpServletResponse resp) {
        // 如果是Ajax请求,创建ResultEntity对象，传入message
        ResultEntity<Object> resultEntity = ResultEntity.failed(exception.getMessage());
        // 创建Gson对象
        Gson gson = new Gson();
        // 将resultEntity转为json
        String resultEntity_json = gson.toJson(resultEntity);
        // 将json返回给页面
        try {
            resp.getWriter().write(resultEntity_json);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private ModelAndView commonResolver(
            // 视图名
            String viewName,
            // 实际捕获的异常
            Exception exception,
            // 当前请求
            HttpServletRequest request,
            // 响应对象
            HttpServletResponse resp,
            // 模型和视图
            ModelAndView modelAndView
    ) {
        // 判断当前请求类型
        Boolean isAjaxRequest = CrowdUtils.isAjaxRequest(request);

        if (isAjaxRequest) {
            // 如果是ajax请求
            ajaxRequestResolver(exception, resp);
            return null;
        }
        // 不是Ajax请求，返回模型和视图
        return commonRequestResolver(viewName, modelAndView, exception);
    }

}
